<script setup lang="ts">
// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 模块导入 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

import { computed, nextTick, reactive, ref, shallowRef, watch } from 'vue';
import type { TreeOption } from 'naive-ui';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
import { fetchAddCjTask, fetchGetCjProjectOptions, fetchGetOrgUnitTree, fetchUpdateCjTask } from '@/service/api';
import { useDict } from '@/hooks/business/dict';
import { TreeUtil } from '@/utils/z';

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 组件名称 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

defineOptions({
  name: 'CjTaskOperateDrawer'
});

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 组合式函数 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

const { formRef, validate, restoreValidation } = useNaiveForm();

const { defaultRequiredRule } = useFormRules();

const { dictOptions } = useDict();

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 父子传参 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

export type OperateType = NaiveUI.TableOperateType | 'view';

interface Props {
  operateType: OperateType;
  rowData?: Api.Sampling.Task | null;
}

const props = defineProps<Props>();

interface Emits {
  (e: 'submitted'): void;
}

const emit = defineEmits<Emits>();

const visible = defineModel<boolean>('visible', {
  default: false
});

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 框架模型 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

const isAdd = computed(() => props.operateType === 'add');

// const isEdit = computed(() => props.operateType === 'edit');

// const isView = computed(() => props.operateType === 'view');

const title = computed(() => {
  const titles: Record<OperateType, string> = {
    add: $t('common.add'),
    edit: $t('common.edit'),
    view: $t('common.view')
  };
  return titles[props.operateType];
});

type Model = Api.Sampling.TaskEdit;

const model: Model = reactive(createDefaultModel());

function createDefaultModel(): Model {
  return {
    id: '',
    projectId: '',
    orgId: '',
    year: '',
    samplingType: '1',
    code: '',
    positionType: '1',
    province: '',
    city: '',
    county: '',
    town: '',
    village: '',
    team: '',
    wgs84Longitude: '',
    wgs84Latitude: '',
    wgs84Altitude: '',
    landUse: '',
    protectionStrategy: '',
    soilType: '',
    soilClass: '',
    subClass: '',
    soilMaterial: '',
    mainCrop: '',
    cropType: '',
    cropTypeManual: ''
  };
}

type RuleKey = Extract<
  keyof Api.Sampling.TaskEdit,
  | 'projectId'
  | 'orgId'
  | 'year'
  | 'samplingType'
  | 'code'
  | 'positionType'
  | 'province'
  | 'city'
  | 'landUse'
  | 'wgs84Longitude'
  | 'wgs84Latitude'
  | 'soilType'
  | 'soilClass'
  | 'subClass'
  | 'soilMaterial'
  | 'protectionStrategy'
  | 'mainCrop'
  | 'cropType'
  | 'cropTypeManual'
>;

const rules: Record<RuleKey, App.Global.FormRule> = {
  projectId: defaultRequiredRule,
  orgId: defaultRequiredRule,
  year: defaultRequiredRule,
  samplingType: defaultRequiredRule,
  code: defaultRequiredRule,
  positionType: defaultRequiredRule,
  province: defaultRequiredRule,
  city: defaultRequiredRule,
  landUse: defaultRequiredRule,
  wgs84Longitude: defaultRequiredRule,
  wgs84Latitude: defaultRequiredRule,
  soilType: defaultRequiredRule,
  soilClass: defaultRequiredRule,
  subClass: defaultRequiredRule,
  soilMaterial: defaultRequiredRule,
  protectionStrategy: defaultRequiredRule,
  mainCrop: defaultRequiredRule,
  cropType: {
    required: model.mainCrop === '4',
    message: '请输入作物类别'
  },
  cropTypeManual: {
    required: ['5', '6'].includes(model.mainCrop),
    message: '请输入作物类别'
  }
};

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 业务模型 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

const projectOptions = shallowRef<CommonType.Option[]>([]);

const myOrgTree = shallowRef<Api.SystemManage.OrgUnitTree[]>([]);

const orgTreeOptions = shallowRef<TreeOption[]>([]);

const provinceOptions = shallowRef<CommonType.Option[]>([]);

const cityOptions = shallowRef<CommonType.Option[]>([]);

const countyOptions = shallowRef<CommonType.Option[]>([]);

const subClassOptions = shallowRef<Api.SystemManage.DictOptions[]>([]);

const soilMaterialOptions = shallowRef<Api.SystemManage.DictOptions[]>([]);

const cropTypeOptions = shallowRef<Api.SystemManage.DictOptions[]>([]);

// 本页面存在树下拉列表，需要在模型初始化时进行控制重新渲染
const treeSelectShow = ref<boolean>(false);

// 重渲染规则控制
const cropTypeVisible = ref<boolean>(false);

const cropTypeManualVisible = ref<boolean>(false);

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 框架方法 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

async function handleInitModel() {
  treeSelectShow.value = false;
  Object.assign(model, createDefaultModel());
  initAllProjectOptions();
  await initOrgTreeOptions();
  setProvinceOptions();
  if (props.operateType === 'edit' && props.rowData) {
    Object.assign(model, props.rowData);
    if (model.province) setCityOptions(model.province);
    if (model.city) setCountyOptions(model.city);
    setSubClassOptions(model.soilClass);
    setSoilMaterialOptions(model.soilClass);
    setCropTypeOptions(model.mainCrop);
    rules.cropType.required = model.mainCrop === '4';
    cropTypeVisible.value = rules.cropType.required;
    rules.cropTypeManual.required = ['5', '6'].includes(model.mainCrop);
    cropTypeManualVisible.value = rules.cropTypeManual.required;
  }
  treeSelectShow.value = true;
}

async function handleSubmit() {
  await validate();
  const func = isAdd.value ? fetchAddCjTask : fetchUpdateCjTask;
  const { error, data } = await func(model);
  if (!error && data) {
    window.$message?.success(isAdd.value ? $t('common.addSuccess') : $t('common.updateSuccess'));
    closeDrawer();
    emit('submitted');
  }
}

function closeDrawer() {
  visible.value = false;
}

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 业务方法 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

// 处理采样项目下拉列表
async function initAllProjectOptions() {
  const { error, data } = await fetchGetCjProjectOptions();
  if (!error && data) {
    projectOptions.value = data;
  }
}

// 初始化组织树下拉列表
async function initOrgTreeOptions() {
  const { error, data } = await fetchGetOrgUnitTree();
  if (!error && data) {
    myOrgTree.value = data;
    orgTreeOptions.value = data.map(toTreeOptionNode);
  }
}

function toTreeOptionNode(item: Api.SystemManage.OrgUnitTree): TreeOption {
  const option: TreeOption = {
    key: item.id,
    label: item.name
  };
  if (item.children && item.children.length > 0) {
    option.children = item.children.map(toTreeOptionNode);
  }
  return option;
}

// 设置省下拉列表
function setProvinceOptions() {
  const tempOptions: CommonType.Option[] = [];
  myOrgTree.value.forEach(item => {
    const option: CommonType.Option = {
      value: item.id,
      label: item.name
    };
    tempOptions.push(option);
  });
  provinceOptions.value = tempOptions;
}

// 处理省值手动选择更新，需要处理关联市值、市下拉列表、县值、县下拉列表
function handleProvinceUpdate(value: string) {
  model.city = '';
  cityOptions.value = [];
  model.county = '';
  countyOptions.value = [];
  setCityOptions(value);
}

function setCityOptions(provinceId: string) {
  const org = TreeUtil.findNodeInOrgTree(myOrgTree.value, provinceId);
  if (org && org.children && org.children.length > 0) {
    const tempOptions: CommonType.Option[] = [];
    org.children.forEach(item => {
      const option: CommonType.Option = {
        value: item.id,
        label: item.name
      };
      tempOptions.push(option);
    });
    cityOptions.value = tempOptions;
  }
}

// 处理市值手动选择更新，需要关联设置县值、县下拉列表
function handleCityUpdate(value: string) {
  model.county = '';
  countyOptions.value = [];
  setCountyOptions(value);
}

function setCountyOptions(cityId: string) {
  const org = TreeUtil.findNodeInOrgTree(myOrgTree.value, cityId);
  if (org && org.children && org.children.length > 0) {
    const tempOptions: CommonType.Option[] = [];
    org.children.forEach(item => {
      const option: CommonType.Option = {
        value: item.id,
        label: item.name
      };
      tempOptions.push(option);
    });
    countyOptions.value = tempOptions;
  }
}

// 处理土类名称手动选择更新，需要关联设置作物类型值、下拉列表
function handleSoilClassUpdate(val: string) {
  model.subClass = '';
  setSubClassOptions(val);
  model.soilMaterial = '';
  setSoilMaterialOptions(val);
}

function setSubClassOptions(val: string) {
  subClassOptions.value = dictOptions('cj_sub_class').filter(x => x.relateDictItemValue === val);
}

function setSoilMaterialOptions(val: string) {
  soilMaterialOptions.value = dictOptions('cj_soil_material').filter(x => x.relateDictItemValue === val);
}

// 处理主产农作物值手动选择更新，需要关联设置作物类型值、下拉列表
function handleMainCropUpdate(val: string) {
  model.cropType = '';
  model.cropTypeManual = '';
  setCropTypeOptions(val);
}

function setCropTypeOptions(val: string) {
  cropTypeOptions.value = [];
  if (['4'].includes(val)) {
    cropTypeOptions.value = dictOptions('cj_crop_type').filter(x => x.relateDictItemValue === val);
  }
  rules.cropType.required = model.mainCrop === '4';
  cropTypeVisible.value = rules.cropType.required;
  rules.cropTypeManual.required = ['5', '6'].includes(model.mainCrop);
  cropTypeManualVisible.value = rules.cropTypeManual.required;
}

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 框架生命周期 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

watch(visible, () => {
  if (visible.value) {
    handleInitModel();
    restoreValidation();
  }
});

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 业务生命周期 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++
</script>

<template>
  <NDrawer v-model:show="visible" display-directive="show" :width="360">
    <NDrawerContent :title="title" :native-scrollbar="false" closable>
      <NForm ref="formRef" :model="model" :rules="rules">
        <NFormItem :label="$t('page.sampling.task.projectId')" path="projectId">
          <NSelect v-model:value="model.projectId" :options="projectOptions"></NSelect>
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.orgId')" path="orgId">
          <template v-if="treeSelectShow">
            <NTreeSelect :options="orgTreeOptions" :default-value="model.orgId" @update:value="val => (model.orgId = val)" />
          </template>
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.year')" path="year">
          <NInput v-model:value="model.year" :placeholder="$t('page.sampling.task.form.year')" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.samplingType')" path="samplingType">
          <NSelect
            v-model:value="model.samplingType"
            :placeholder="$t('page.sampling.task.form.samplingType')"
            :options="dictOptions('cj_sampling_type')"
          />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.code')" path="code">
          <NInput v-model:value="model.code" :placeholder="$t('page.sampling.task.form.code')" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.positionType')" path="positionType">
          <NSelect
            v-model:value="model.positionType"
            :placeholder="$t('page.sampling.task.form.positionType')"
            :options="dictOptions('cj_position_type')"
          />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.province')" path="province">
          <NSelect v-model:value="model.province" :options="provinceOptions" @update:value="handleProvinceUpdate"></NSelect>
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.city')" path="city">
          <NSelect v-model:value="model.city" :options="cityOptions" @update:value="handleCityUpdate"></NSelect>
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.county')" path="county">
          <NSelect v-model:value="model.county" :options="countyOptions" clearable></NSelect>
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.town')" path="town">
          <NInput v-model:value="model.town" :placeholder="$t('page.sampling.task.form.town')" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.village')" path="country">
          <NInput v-model:value="model.village" :placeholder="$t('page.sampling.task.form.village')" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.team')" path="team">
          <NInput v-model:value="model.team" :placeholder="$t('page.sampling.task.form.team')" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.wgs84Longitude')" path="wgs84Longitude">
          <NInput v-model:value="model.wgs84Longitude" :placeholder="$t('page.sampling.task.form.wgs84Longitude')" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.wgs84Latitude')" path="wgs84Latitude">
          <NInput v-model:value="model.wgs84Latitude" :placeholder="$t('page.sampling.task.form.wgs84Latitude')" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.wgs84Altitude')" path="wgs84Altitude">
          <NInput v-model:value="model.wgs84Altitude" :placeholder="$t('page.sampling.task.form.wgs84Altitude')" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.landUse')" path="landUse">
          <NSelect v-model:value="model.landUse" :placeholder="$t('page.sampling.task.form.landUse')" :options="dictOptions('cj_land_use')" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.protectionStrategy')" path="protectionStrategy">
          <NSelect
            v-model:value="model.protectionStrategy"
            :placeholder="$t('page.sampling.task.form.protectionStrategy')"
            :options="dictOptions('cj_protection_strategy')"
          />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.soilType')" path="soilType">
          <NSelect v-model:value="model.soilType" :placeholder="$t('page.sampling.task.form.soilType')" :options="dictOptions('cj_soil_type')" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.soilClass')" path="soilClass">
          <NSelect
            v-model:value="model.soilClass"
            :placeholder="$t('page.sampling.task.form.soilClass')"
            :options="dictOptions('cj_soil_class')"
            @update:value="handleSoilClassUpdate"
          />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.subClass')" path="subClass">
          <NSelect v-model:value="model.subClass" :placeholder="$t('page.sampling.task.form.subClass')" :options="subClassOptions" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.soilMaterial')" path="soilMaterial">
          <NSelect v-model:value="model.soilMaterial" :placeholder="$t('page.sampling.task.form.soilMaterial')" :options="soilMaterialOptions" />
        </NFormItem>
        <NFormItem :label="$t('page.sampling.task.mainCrop')" path="mainCrop">
          <NSelect
            v-model:value="model.mainCrop"
            :placeholder="$t('page.sampling.task.form.mainCrop')"
            :options="dictOptions('cj_main_crop')"
            @update:value="handleMainCropUpdate"
          />
        </NFormItem>
        <template v-if="cropTypeVisible">
          <NFormItem :label="$t('page.sampling.task.cropType')" path="cropType">
            <NSelect v-model:value="model.cropType" :placeholder="$t('page.sampling.task.form.cropType')" :options="cropTypeOptions" />
          </NFormItem>
        </template>
        <template v-if="cropTypeManualVisible">
          <NFormItem label="作物类别" path="cropTypeManual">
            <NInput v-model:value="model.cropTypeManual" :placeholder="$t('page.sampling.task.form.cropType')" />
          </NFormItem>
        </template>
      </NForm>
      <template #footer>
        <NSpace>
          <NButton quaternary @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
          <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
        </NSpace>
      </template>
    </NDrawerContent>
  </NDrawer>
</template>

<style scoped></style>
